package moodish.dummy;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;

import moodish.comm.ClientComm;
import moodish.comm.ClientSideMessage;
import moodish.comm.MessageFromServer;
import moodish.comm.MessageToServer;
import moodish.comm.ServerSideMessage.Type;

public class ClientCommDummy implements ClientComm {
 
        public static final int PORT = 8085;
 
        private String nickname;
 
        private ObjectInputStream clienteSocketIn;
        private ObjectOutputStream clienteSocketOut;
 
        private LinkedList<MessageFromServer> messages = new LinkedList<MessageFromServer>();
 
        private Socket socket;
        private Thread comm;
 
        /**
         * Start's a new connect for the ServerAdress with the nickname
         *
         * @param String serverAddress the name or server ip address
         * @param String nickname to be connected with
         *
         * @throws IOException Other error occured while trying to connect
         * @throws UnknownHostException couldn't connect to the server
         */
        @Override
        public void connect(String serverAddress, String nickname)
                        throws IOException, UnknownHostException {
                this.nickname = nickname;
 
                // Get the inet address for the name/IP
                InetAddress address = InetAddress.getByName(serverAddress);
                // Try to connect to the PORT with the inetAddress
                socket = new Socket(address, PORT);
 
                // Create Objects Out and Input Stream object
                clienteSocketOut = new ObjectOutputStream(socket.getOutputStream());
                clienteSocketIn = new ObjectInputStream(socket.getInputStream());
 
                // Send connection message
                MessageToServer msg = new MessageToServer(nickname, null,
                                Type.CLIENT_CONNECTED);
                sendMessage(msg);
 
                // Start's a new listenner for the server messages
                comm = new Thread(new Runnable() {
 
                        @Override
                        public void run() {
                                try {
                                        while (!Thread.interrupted()) {
                                                MessageFromServer msg;
 
                                                // Read the messages in the socket
                                                try {
                                                        msg = (MessageFromServer) clienteSocketIn.readObject();
                                                        // Insert messages into the list
                                                        receiveMessage(msg);
                                                } catch (ClassNotFoundException e) {
                                                        // Couldn't read the message
                                                }
 
                                        }
                                } catch (IOException e) {
                                        // IO ERROR
                                }
                        }
                });
               
                comm.start();
        }
 
        /**
         * Receive a new message
         *
         * @param String msg received
         */
        public synchronized void receiveMessage(MessageFromServer msg) {
                messages.addLast(msg);
               
                notifyAll();
        }
 
        /**
         * Confirm the present connection
         */
        @Override
        public boolean isConnected() {
                if (socket == null)
                        return false;
                return socket.isConnected();
        }
       
        /**
         * disconnect client
         *
         * Send message to the server asking for disconnect
         */
        @Override
        public void disconnect() {
                // Close the connection
                MessageToServer msg = new MessageToServer(nickname, null,
                                Type.CLIENT_DISCONNECTED);
                try {
                        clienteSocketOut.writeObject(msg);
                } catch (IOException e) {
                        // IO error while sending the message
                }              
               
                // interrupt the messages from server listener
                comm.interrupt();
 
 
                try {
                        socket.close();
                } catch (IOException e) {
                        // error while closing the socket
                }
        }
 
        /**
         * Confirm if there is a unread message
         *
         * @return boolean is some unread message
         */
        @Override
        public boolean hasNextMessage() {
                // Check if there is some message waiting for receive
                return (messages.size() > 0);
        }
 
        /**
         * Get the next message on the list
         *
         * @return ClientSideMessage msg receive or null in case of fail
         */
        @Override
        public synchronized ClientSideMessage getNextMessage() {
                // get the next message on the list
                try {
                        if (isConnected()) {
                                while (!hasNextMessage()) {
                                        wait();
                                }
 
                                MessageFromServer msg = messages.getFirst();
                                messages.removeFirst();
 
                                return msg;
                        }
                } catch (InterruptedException e) {
                        // error while waiting
                }
 
                return null;
        }
 
        /**
         * Send unfriendship
         *
         * @param String moodish message sent to the server
         */
       
        @Override
        public void sendMoodishMessage(String moodishMessage) {
                // Send a modish message
                MessageToServer msg = new MessageToServer(nickname, moodishMessage,
                                Type.MOODISH_MESSAGE);
                sendMessage(msg);
        }
 
        /**
         * Send friendship
         *
         * @param String nickname target nickname to be friend
         */
        @Override
        public void friendship(String nickname) {
                // Ask friendship to
                MessageToServer msg = new MessageToServer(this.nickname, nickname,
                                Type.FRIENDSHIP);
                sendMessage(msg);
        }
 
        /**
         * Send unfriendship
         *
         * @param String nickname target nickname to unfrined
         */
        @Override
        public void unfriendship(String nickname) {
                // End friendship with
                MessageToServer msg = new MessageToServer(this.nickname, nickname,
                                Type.UNFREINDSHIP);
                sendMessage(msg);
        }
 
        /**
         * Send a message to the server through the output channel
         *
         * @param msg MessageToServer
         */
        private void sendMessage(MessageToServer msg) {
                // Send the message to the server
                try {
                        clienteSocketOut.writeObject(msg);
                } catch (IOException e) {
                        // IO error while sending the message
                        disconnect();
                }
        }
}